package com.xique.door.biz.service.impl;

import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.door.bean.domain.*;
import com.xique.door.bean.dto.DeviceBuildingInfoDTO;
import com.xique.door.bean.search.AccessDeviceListSearch;
import com.xique.door.bean.search.build.AreaListSearch;
import com.xique.door.bean.search.build.HouseUserListSearch;
import com.xique.door.biz.service.IBuildingDeviceBizService;
import com.xique.door.command.ICardCommandBizService;
import com.xique.door.command.IDeviceUserCommandService;
import com.xique.door.constant.UserConstant;
import com.xique.door.device.freeview.constant.CommandStatus;
import com.xique.door.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shd
 * @create 2022/1/29 13:35
 */
@Service
public class BuildingDeviceBizServiceImpl implements IBuildingDeviceBizService {

    @Autowired
    private IBuildBuildingService buildingService;

    @Autowired
    private IBuildAreaService areaService;

    @Autowired
    private IBuildingDeviceService buildingDeviceService;

    @Autowired
    private IBuildElevatorService elevatorService;

    @Autowired
    private IBuildHouseUserService houseUserService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IDeviceUserCommandService deviceUserCommandService;

    @Autowired
    private IUserDeviceService userDeviceService;

    @Autowired
    private IParkInfoService parkInfoService;

    @Autowired
    private IAccessDeviceService accessDeviceService;

    @Autowired
    private IDCardHouseService cardHouseService;

    @Autowired
    private IDCardService cardService;

    @Autowired
    private IDCardDeviceService cardDeviceService;

    @Autowired
    private ICardCommandBizService cardCommandBizService;

    @Override
    public boolean insertBuildingDevice(AccessDevice accessDevice, String foreignType, Long foreignId) {
        Long parkId = SecurityUtils.getParkId();
        List<BuildingDevice> list = new ArrayList<>();

        if ("park".equals(foreignType)) {
            AreaListSearch search = new AreaListSearch();
            search.setParkId(foreignId);
            List<BuildAreaV1> areaList = areaService.selectAreaListV1(search);
            List<Long> areaIds = areaList.stream().map(BuildAreaV1::getId).distinct().collect(Collectors.toList());
            List<BuildBuilding> buildingList = buildingService.selectBuildBuildingListByAreaIds(areaIds);
            for (BuildBuilding building : buildingList) {
                BuildingDevice buildingDevice = new BuildingDevice();
                buildingDevice.setParkId(parkId);
                buildingDevice.setDeviceId(accessDevice.getId());
                buildingDevice.setBuildingId(building.getId());
                list.add(buildingDevice);
            }
        }

        if ("gate".equals(foreignType)) {
            // 添加到该区域下所有楼栋
            List<BuildBuilding> buildingList = buildingService.selectBuildBuildingListByAreaIds(Collections.singletonList(foreignId));
            for (BuildBuilding building : buildingList) {
                BuildingDevice buildingDevice = new BuildingDevice();
                buildingDevice.setParkId(parkId);
                buildingDevice.setDeviceId(accessDevice.getId());
                buildingDevice.setBuildingId(building.getId());
                list.add(buildingDevice);
            }
        }

        if ("cell".equals(foreignType)) {
            BuildingDevice buildingDevice = new BuildingDevice();
            buildingDevice.setParkId(parkId);
            buildingDevice.setDeviceId(accessDevice.getId());
            buildingDevice.setBuildingId(foreignId);
            list.add(buildingDevice);
        }

        if ("elevator".equals(foreignType)) {
            BuildElevator elevator = elevatorService.getById(foreignId);
            BuildingDevice buildingDevice = new BuildingDevice();
            buildingDevice.setParkId(parkId);
            buildingDevice.setDeviceId(accessDevice.getId());
            buildingDevice.setBuildingId(elevator.getBuildingId());
            list.add(buildingDevice);
        }

        if (CollectionUtils.isEmpty(list)) {
            return true;
        }

        int count = buildingDeviceService.insertBuildingDevices(list);
        if (count <= 0) {
            return false;
        }

        // TODO 下发用户信息到设备
        List<Long> buildingIds = list.stream().map(BuildingDevice::getBuildingId).collect(Collectors.toList());
        HouseUserListSearch search = new HouseUserListSearch();
        search.setBuildingIds(buildingIds);
        List<BuildHouseUserV1> houseUserList = houseUserService.selectHouseUserListV1(search);
        List<Long> userIds = houseUserList.stream().map(BuildHouseUserV1::getUserId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(userIds)) {
            List<User> userList = userService.selectUserByIds(userIds);
            List<User> downUserList = userList.stream().filter(item -> StringUtils.isNotEmpty(item.getFaceUrl())).collect(Collectors.toList());

            List<UserDevice> userDevices = new ArrayList<>();
            for (User user : userList) {
                UserDevice userDevice = new UserDevice();
                userDevice.setParkId(user.getParkId());
                userDevice.setModel(accessDevice.getModel());
                userDevice.setUserId(user.getId());
                userDevice.setDeviceId(accessDevice.getId());
                userDevice.setDevSn(accessDevice.getDevSn());
                if (StringUtils.isEmpty(accessDevice.getOnlineStatus()) || "offline".equals(accessDevice.getOnlineStatus())) {
                    userDevice.setStatus(CommandStatus.PENDING);
                } else {
                    if (StringUtils.isNotEmpty(user.getFaceUrl())) {
                        userDevice.setStatus(CommandStatus.SEND);
                    } else {
                        userDevice.setStatus(CommandStatus.NOFACE);
                    }
                }
                userDevice.setCustomId(user.getCustomId());
                userDevice.setModel(accessDevice.getModel());
                userDevice.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
                userDevices.add(userDevice);
            }
            int i = userDeviceService.batchInsertUserDevice(userDevices);

            deviceUserCommandService.downDevicesUsers(Collections.singletonList(accessDevice), downUserList);
        }

        // TODO 下发卡到设备()
        List<Long> houseIds = houseUserList.stream().map(BuildHouseUserV1::getHouseId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(houseIds)) {
            List<DCardHouse> cardHouseList = cardHouseService.selectCardHouseListByHouseIds(houseIds);
            if (CollectionUtils.isNotEmpty(cardHouseList)) {
                List<Long> cardIds = cardHouseList.stream().map(DCardHouse::getCardId).distinct().collect(Collectors.toList());
                List<DCard> cardList = cardService.selectDCardByIds(cardIds, UserConstant.Status.NORMAL);
                if (CollectionUtils.isNotEmpty(cardList)) {
                    List<Long> cardUserIds = cardList.stream().map(DCard::getUserId).distinct().collect(Collectors.toList());
                    List<User> cardUserList = userService.selectUserByIds(cardUserIds);
                    Map<Long, User> cardUserMap = cardUserList.stream().collect(Collectors.toMap(User::getId, v -> v));

                    List<CardDevice> cardDevices = new ArrayList<>();
                    for (DCard card : cardList) {
                        CardDevice cardDevice = new CardDevice();
                        cardDevice.setDeviceId(accessDevice.getId());
                        cardDevice.setParkId(card.getParkId());
                        cardDevice.setCustomId(card.getCustomId());
                        cardDevice.setCardSn(card.getCardSn());
                        cardDevice.setModel(accessDevice.getModel());
                        cardDevice.setStatus(CommandStatus.SEND);
                        cardDevice.setDevSn(accessDevice.getDevSn());
                        cardDevice.setCardId(card.getId());
                        cardDevice.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
                        cardDevice.setUpdateBy(cardDevice.getCreateBy());
                        if (StringUtils.isNotNull(cardUserMap.get(card.getUserId()))) {
                            User cardUser = cardUserMap.get(card.getUserId());
                            card.setUserName(cardUser.getUserName());
                            card.setPersonType(cardUser.getPersonType());
                        }
                        cardDevices.add(cardDevice);
                    }

                    cardDeviceService.batchInsertCardDevices(cardDevices);

                    cardCommandBizService.downCards(Collections.singletonList(accessDevice), cardList);
                }
            }
        }
        return true;
    }

    @Override
    public DeviceBuildingInfoDTO selectDeviceBuildingInfo(Long foreignId, String foreignType) {
        DeviceBuildingInfoDTO dto = new DeviceBuildingInfoDTO();
        if ("elevator".equals(foreignType)) {
            BuildElevator elevator = elevatorService.getById(foreignId);
            dto.setElevatorId(elevator.getId());
            dto.setElevatorName(elevator.getName());
            foreignId = elevator.getBuildingId();
            foreignType = "cell";
        }
        if ("cell".equals(foreignType)) {
            BuildBuilding building = buildingService.selectBuildBuildingById(foreignId);
            dto.setBuildingId(building.getId());
            dto.setBuildingName(building.getBuildingName());
            foreignId = building.getAreaId();
            foreignType = "gate";
        }
        if ("gate".equals(foreignType)) {
            BuildArea area = areaService.selectBuildAreaById(foreignId);
            dto.setAreaId(area.getId());
            dto.setAreaName(area.getAreaName());
        }
        if ("park".equals(foreignType)) {
            ParkInfo parkInfo = parkInfoService.selectParkInfoById(foreignId);
            dto.setParkId(parkInfo.getId());
            dto.setParkName(parkInfo.getName());
        }
        return dto;
    }

    @Override
    public boolean insertBuildingDevice(List<BuildBuilding> buildings) {

        if (CollectionUtils.isEmpty(buildings)) {
            return true;
        }

        Long areaId = buildings.get(0).getAreaId();
        Long parkId = buildings.get(0).getParkId();

        AccessDeviceListSearch search = new AccessDeviceListSearch();
        search.setForeignId(areaId);
        List<AccessDeviceV1> areaDeviceList = accessDeviceService.selectAccessDeviceList(search);

        search.setForeignId(parkId);
        List<AccessDeviceV1> parkDeviceList = accessDeviceService.selectAccessDeviceList(search);

        List<BuildingDevice> list = new ArrayList<>();

        for (BuildBuilding building : buildings) {
            if (CollectionUtils.isNotEmpty(areaDeviceList)) {
                for (AccessDeviceV1 accessDevice : areaDeviceList) {
                    BuildingDevice buildingDevice = new BuildingDevice();
                    buildingDevice.setParkId(parkId);
                    buildingDevice.setBuildingId(building.getId());
                    buildingDevice.setDeviceId(accessDevice.getId());
                    list.add(buildingDevice);
                }
            }
            if (CollectionUtils.isNotEmpty(parkDeviceList)) {
                for (AccessDeviceV1 accessDevice : parkDeviceList) {
                    BuildingDevice buildingDevice = new BuildingDevice();
                    buildingDevice.setParkId(parkId);
                    buildingDevice.setBuildingId(building.getId());
                    buildingDevice.setDeviceId(accessDevice.getId());
                    list.add(buildingDevice);
                }
            }
        }

        int count = buildingDeviceService.insertBuildingDevices(list);
        if (count <= 0) {
            return false;
        }

        return true;
    }
}
